package net.zoneland.knowledge.service;

import java.util.List;

import net.zoneland.knowledge.enums.WorkStatusEnum;
import net.zoneland.knowledge.enums.WorkStatusOfSubTaskEnum;
import net.zoneland.knowledge.enums.WorkSubTaskNodeEnum;
import net.zoneland.knowledge.exceptions.WorkApplyException;
import net.zoneland.knowledge.model.LoginUserPojo;
import net.zoneland.knowledge.model.WorkApplyInfo;
import net.zoneland.knowledge.model.WorkApplyInfoAttachment;
import net.zoneland.knowledge.model.WorkSubTaskInfo;
import net.zoneland.uniflow.client.TaskObject;
import net.zoneland.uniflow.client.UserInfo;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.tuple.Pair;

/**
 * 分任务的内部服务接口。
 * <p>所谓内部服务，即不对上层（Controller）开放，只对其他服务层代码（XXService）提供公共服务</p>
 */
public interface WorkSubTaskInternalService {
    /**
     * 任务id为空提示语.
     */
    public static final String TASK_ID_BLANK_ERROR_MSG = "任务id不能为空！";
    /**
     * 工单信息不存在提示语.
     */
    public static final String APPLY_NOT_EXISTS_ERROR_MSG = "工单信息不存在!";
    /**
     * 获取全局锁失败.
     */
    public static final String GET_LOCK_FAILED = "当前工单其他用户正在操作，请稍后再试或联系管理员！";

    /**
     * 确认分任务。
     *
     * @param info         主工单对象
     * @param subApplyList 要确认分任务的子工单对象
     * @param allFinish    主工单下所有分任务是否都确认了
     */
    void confirmSubTasks(final WorkApplyInfo info, final List<WorkApplyInfo> subApplyList, final boolean allFinish);

    /**
     * 确认分任务，实质是更新分任务的状态及其父级分任务的状态。
     *
     * @param currentApplyInfo 当前工单（是需要确认的分任务的上级工单）
     * @param subTaskInfoList  要确认的分任务列表
     * @param user
     * @return 收到影响的父级分任务（并非每个父级分任务都会收到影响）
     */
    List<WorkSubTaskInfo> confirmSubTasks(final WorkApplyInfo currentApplyInfo, final List<WorkSubTaskInfo> subTaskInfoList,
                                          final LoginUserPojo user);

    /**
     * 退回分任务，实质是更新分任务的状态。
     *
     * @param subTaskInfoList 要退回的分任务列表
     */
    void rejectSubTasks(final List<WorkSubTaskInfo> subTaskInfoList);

    /**
     * 上报分任务。
     *
     * @param list 需要上报的分任务列表
     */
    void reportSubTasks(final List<WorkSubTaskInfo> list);

    /**
     * 上报工单，实质是工单里的分任务要上报，分任务上报后要更新工单的状态和处理人。
     *
     * @param info    要上报的工单
     * @param taskId  流程平台的任务tiid
     * @param subTaskInfos 分任务信息
     * @param user    当前用户
     * @param opinion 处理意见
     */
    void reportWorkApply(final WorkApplyInfo info, final String taskId, final List<WorkSubTaskInfo> subTaskInfos, final LoginUserPojo user, final String opinion);

    /**
     * 更新指定工单下的所有分任务的状态。
     *
     * @param info       主工单对象，要把此工单下的所有分任务的状态都更新了
     * @param targetNode 要更新的状态
     */
    void updateSubTasksNode(final WorkApplyInfo info, final WorkSubTaskNodeEnum targetNode);

    /**
     * 更新指定分任务的状态。
     *
     * @param subTaskInfoList 需要更新的分任务对象列表
     * @param targetNode      要更新的状态
     */
    void updateSubTasksNode(final List<WorkSubTaskInfo> subTaskInfoList, final WorkSubTaskNodeEnum targetNode);

    /**
     * 根据分任务状态来计算工单状态。
     * <p>
     * <li>有任何一个分任务在办理，工单就算办理状态</li>
     * <li>所有分任务都完成，工单才算完成</li>
     * <li>分任务已上报和已下发的混合状态（可能还有完成的），工单状态：等待上级确认和下级上报</li>
     * <li>分任务全部上报（可能还有完成的），工单状态：等待上级确认</li>
     * <li>分任务全部已下发（可能还有完成的），工单状态：等待下级上报</li>
     * </p>
     *
     * @param info 工单对象
     * @return 计算出来的工单状态
     */
    WorkStatusOfSubTaskEnum calculateWorkApplyStatusBySubTasks(final WorkApplyInfo info);

    /**
     * 根据分任务状态来计算工单状态。
     * <p>
     * <li>有任何一个分任务在办理，工单就算办理状态</li>
     * <li>所有分任务都完成，工单才算完成</li>
     * <li>分任务已上报和已下发的混合状态（可能还有完成的），工单状态：等待上级确认和下级上报</li>
     * <li>分任务全部上报（可能还有完成的），工单状态：等待上级确认</li>
     * <li>分任务全部已下发（可能还有完成的），工单状态：等待下级上报</li>
     * </p>
     *
     * @param subTaskInfos 该工单下所有分任务对象
     * @return 计算出来的工单状态
     */
    WorkStatusOfSubTaskEnum calculateWorkApplyStatusBySubTasks(final List<WorkSubTaskInfo> subTaskInfos);

    /**
     * 在流程操作之前做的通用校验.
     *
     * @param workApplyInfo 工单信息
     * @param status        此流程操作的合法状态，工单应该在此状态
     * @param user          当前用户，工单的处理人应该是此用户
     */
    void checkDataBeforeApprove(final WorkApplyInfo workApplyInfo, final WorkStatusEnum status, final LoginUserPojo user);

    /**
     * 更新父工单信息，并将父流程的待办任务提交到下一节点确认环节.
     * <p>父工单的流程处理逻辑是：只要有任何一个下级分任务上报上来，就要流转到确认环节</p>
     * <p>如果上报上来的分任务已处理，还有其他没有上报上来的分任务，此时流程就停留在确认环节（有待办）</p>
     *
     * @param info    工单信息
     * @param user    操作用户
     * @param opinion 意见
     * @return 父工单对象和操作后的任务列表
     */
    Pair<WorkApplyInfo, List<TaskObject>> submitParentApplyWhenSubApplySubmit(final WorkApplyInfo info, final LoginUserPojo user, final String opinion);

    /**
     * 完整的更新工单对象.
     * <p>
     *     更新内容包括：
     *     <li>工单对象本身</li>
     *     <li>工单对象所关联的参考附件和结果附件，没有则不更新（也不删除原有的）</li>
     *     <li>工单里的分任务对象，没有则不更新（也不删除原有的）</li>
     *     <li>工单里的分任务的结果附件，没有则不更新（也不删除原有的）</li>
     * </p>
     * @param workApplyInfo 要更新的工单对象
     */
    void updateWorkApplyFully(final WorkApplyInfo workApplyInfo);

    /**
     * 分任务更新.
     *
     * @param workApplyInfo 当前工单
     * @param oldApplyInfo  原工单
     */
    void updateSubTasks(final WorkApplyInfo workApplyInfo, final WorkApplyInfo oldApplyInfo);

    /**
     * 查询工单信息.
     *
     * @param id 工单id
     * @return 工单信息
     */
    WorkApplyInfo findWorkApplyInfoById(String id) throws WorkApplyException;

    /**
     * 通过父工单id查询子工单信息.
     *
     * @param parentId 父工单id
     * @return 工单信息
     */
    public List<WorkApplyInfo> findWorkApplyByParentId(final String parentId);

    /**
     * 插入工单.
     *
     * @param workApplyInfo 工单
     * @param user          当前用户
     */
    void insertWorkApply(final WorkApplyInfo workApplyInfo, LoginUserPojo user);

    /**
     * 更新工单的ApplyId.
     *
     * @param info 工单
     * @param data 流程引擎返回的节点任务信息
     */
    void updateWorkApplyIdAndPiid(final WorkApplyInfo info, final TaskObject[] data);

    /**
     * 创建子流程任务.
     *
     * @param info 工单信息
     * @param user 操作用户
     * @return 任务集合和子工单列表
     */
    Pair<List<TaskObject>, List<WorkApplyInfo>> createSubTask(final WorkApplyInfo info, final LoginUserPojo user);

    /**
     * 创建子流程任务.
     *
     * @param info          工单信息
     * @param subTasks      要分派的分任务列表，可能只是当前工单下的部分分任务
     * @param dispatchUserNames 要分派的人员名单（要分配给这些人），json格式，由选人框产生
     * @param user          操作用户
     * @return 任务集合
     */
    Pair<List<TaskObject>, List<WorkApplyInfo>> createSubTask(final WorkApplyInfo info, final List<WorkSubTaskInfo> subTasks, final String dispatchUserNames, final LoginUserPojo user);

    /**
     * 创建子流程任务.
     *
     * @param info          工单信息
     * @param subTasks      要分派的分任务列表，可能只是当前工单下的部分分任务
     * @param dispatchUsers 要分派的人员名单（要分配给这些人）
     * @param user          操作用户
     * @return 任务集合
     */
    Pair<List<TaskObject>, List<WorkApplyInfo>> createSubTask(final WorkApplyInfo info, final List<WorkSubTaskInfo> subTasks, final List<List<UserInfo>> dispatchUsers, final LoginUserPojo user);

    void initWorkApplyInfoAttachments(HttpServletRequest request, WorkApplyInfo workApplyInfo, LoginUserPojo user);

    void handleReportAttachments(List<WorkSubTaskInfo> subTasks, LoginUserPojo user, HttpServletRequest request);

    void insertMergeAttachments(WorkSubTaskInfo subTaskInfo);

    WorkApplyInfoAttachment findWorkAttachmentById(String attachmentId);

    void checkNeedSuspendTask(WorkApplyInfo currentApplyInfo, List<WorkSubTaskInfo> subTasks);

    void addCopySubmitInfo(final WorkApplyInfo workApplyInfo);
}
